package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.TsCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    //	如果是批量保存： 借助ServiceImpl 实现类： this.saveBatch();

    @Override
    @TsCache(prefix = "statVo:")
    public AlbumStatVo getAlbumStatVo(Long albumId) {
        //	调用mapper 层方法;
        return albumInfoMapper.selectAlbumStatVo(albumId);
    }

    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        //	select * from album_info where user_id = 1;
        //	select id, album_title from album_info where user_id = 1;
        //	List<AlbumInfo> albumInfoList = albumInfoMapper.selectList(new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId).select(AlbumInfo::getId, AlbumInfo::getAlbumTitle).orderByDesc(AlbumInfo::getId));
        //	前端应该传递pageNo,pageSize;
        Page<AlbumInfo> albumInfoPage = new Page<>(1, 10);
        Page<AlbumInfo> infoPage = albumInfoMapper.selectPage(albumInfoPage, new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId).select(AlbumInfo::getId, AlbumInfo::getAlbumTitle).orderByDesc(AlbumInfo::getId));
        //	建立索引：album_title;
        return infoPage.getRecords();
    }

    @Override
    public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
        //	album_info;
        AlbumInfo albumInfo = new AlbumInfo();
        //	属性拷贝：
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        albumInfo.setId(albumId);
        //	更新数据！
        albumInfoMapper.updateById(albumInfo);
        //	album_attribute_value 先删除，再新增!
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        //	album_attribute_value 添加数据！
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        //	判断
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //	创建对象
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //	属性拷贝：
                BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
                //	因为53行执行了insert 方法。所以通过type = IdType.AUTO 属性配置，就能够获取到主键自增的id
                albumAttributeValue.setAlbumId(albumInfo.getId());
                //	保存数据：insert into album_attribute_value values(?,?,?); insert into album_attribute_value values(?,?,?);
                //	insert into album_attribute_value values (?,?,?) (?,?,?) (?,?,?) mybatis-plus 的批量插入！
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }
        //	判断：
        if ("1".equals(albumInfoVo.getIsOpen())) {
            //	上架 需要专辑Id;
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumId);
            //  添加到布隆过滤器;
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            //  将专辑Id添加到过滤器中
            bloomFilter.add(albumId);
        } else {
            //	下架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumId);
        }
    }

    @Override
    @TsCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
    public AlbumInfo getAlbumInfo(Long albumId) {
        //	先查缓存，缓存没有再查询数据;
        //	考虑到数据类型，与key是什么!
        //        String dataKey = RedisConstant.ALBUM_INFO_PREFIX + albumId;
        //        //	从缓存获取;
        //        try {
        //            AlbumInfo albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(dataKey);
        //            //	判断缓存中是否有数据
        //            if (null == albumInfo) {
        //                //	说明缓存中没有数据; Redisson;
        //                String lockKey = RedisConstant.ALBUM_LOCK_SUFFIX + albumId;
        //                RLock lock = redissonClient.getLock(lockKey);
        //                //  上锁;
        //                lock.lock();
        //                try {
        //                    //  查询数据库之前再查一遍缓存;
        //                    albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(dataKey);
        //                    if (null != albumInfo) {
        //                        log.info("查询缓存");
        //                        return albumInfo;
        //                    }
        //                    //  查询数据库;
        //                    albumInfo = getAlbumInfoDB(albumId);
        //                    log.info("查询数据库");
        //                    if (null == albumInfo) {
        //                        //  缓存一个空值;
        //                        this.redisTemplate.opsForValue().set(dataKey, new AlbumInfo(), 10, TimeUnit.MINUTES);
        //                        return new AlbumInfo();
        //                    }
        //                    //  将数据存储到缓存
        //                    this.redisTemplate.opsForValue().set(dataKey, albumInfo, RedisConstant.ALBUM_TIMEOUT, TimeUnit.SECONDS);
        //                    //  返回数据;
        //                    return albumInfo;
        //                } catch (Exception e) {
        //                    throw new RuntimeException(e);
        //                } finally {
        //                    //  解锁;
        //                    lock.unlock();
        //                }
        //            } else {
        //                //  缓存有数据
        //                log.info("查询缓存");
        //                return albumInfo;
        //            }
        //        } catch (RuntimeException e) {
        //            System.out.println(e.getMessage());
        //        }
        //  查询数据库;
        return getAlbumInfoDB(albumId);
    }

    @Nullable
    private AlbumInfo getAlbumInfoDB(Long albumId) {
        AlbumInfo albumInfo = this.getById(albumId);
        //	查询专辑对应属性标签数据
        if (null != albumInfo) {
            //	查询专辑Id 对应的属性集合 select * from album_attribute_value where album_id = ? and is_deleted=0;
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId)));
        }
        return albumInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAlbumInfo(Long albumId) {
        //		album_attribute_value
        //		album_info
        //		album_stat
        albumInfoMapper.deleteById(albumId);
        //	album_attribute_value;
        //	delete from album_attribute_value where album_id = ? and is_delete=0; 物理删除;
        //	update album_attribute_value set is_delete=1 where album_id = ? and is_delete=0; 逻辑删除
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        //	album_stat
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, albumId));
    }

    @Override
    public IPage<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> albumListVoPage, AlbumInfoQuery albumInfoQuery) {
        //	查询数据有专辑基本信息+专辑统计信息; album_info; album_stat;
        return albumInfoMapper.selectUserAlbumPage(albumListVoPage, albumInfoQuery);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {

        //  album_info
        AlbumInfo albumInfo = new AlbumInfo();
        //	属性赋值; 属性拷贝 - 属性一致的；将属性数据平移！
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        //	userId; tracks_for_free; status
        albumInfo.setUserId(userId);
        //	免费试听集数：
        //	判断当前专辑的类型;
        if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfoVo.getPayType())) {
            //	说明付费专辑: 都应该有试听集数;
            albumInfo.setTracksForFree(5);
        }
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
        albumInfoMapper.insert(albumInfo);
        //  album_attribute_value
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        //	判断
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //	创建对象
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //	属性拷贝：
                BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
                //	因为53行执行了insert 方法。所以通过type = IdType.AUTO 属性配置，就能够获取到主键自增的id
                albumAttributeValue.setAlbumId(albumInfo.getId());
                //	保存数据：insert into album_attribute_value values(?,?,?); insert into album_attribute_value values(?,?,?);
                //	insert into album_attribute_value values (?,?,?) (?,?,?) (?,?,?) mybatis-plus 的批量插入！
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }
        //  album_stat
        this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_PLAY);
        this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_SUBSCRIBE);
        this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_BROWSE);
        this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_COMMENT);

        if ("1".equals(albumInfoVo.getIsOpen())) {
            //	上架 需要专辑Id;
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
            //  添加到布隆过滤器;
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            //  将专辑Id添加到过滤器中
            bloomFilter.add(albumInfo.getId());
        }
    }

    public void saveAlbumStat(Long albumId, String statPlay) {
        //	保存数据：
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(albumId);
        albumStat.setStatType(statPlay);
        albumStat.setStatNum(new Random().nextInt(10000000));
        albumStatMapper.insert(albumStat);
    }
}
